<?php
/**
 * Image resizing toolkit for generating thumbnails
 * @author AFV <saviorfromthenorth@yahoo.com.ph>
 * @version 1.0 Beta
 */
class zapImage
{
    /**
     *
     * @var string $error Error message details
     */
    public $error;

    /**
     * Save a form submitted image
     * @param string $destination
     * @return abstract Returns the file path when saved and FALSE on error
     */
    public function save($destination)
    {
        //check if paramter is empty
        if (empty($destination)) {
            $this->error = 'No destination folder';
            return false;
        }

        //format destination string
        if (substr($destination, 0, -1) != '/')
            $destination = $destination . '/';

        //create destination folder if it does not exist
        if (!is_dir($destination))
            mkdir($destination, 0755, true);

        //check for image files on posted file items
        foreach ($_FILES as $key => $data) {
            if (isset($_FILES[$key]['name'])) {
                $extension = explode('.', $_FILES[$key]['name']);
                $extension = $extension[count($extension) - 1];

                switch (strtolower($extension)) {
                case 'png':
                case 'jpg':
                case 'jpeg':
                case 'gif':
                    $file = $_FILES[$key];

                    if (file_exists($destination . $file['name'])) {
                        $this->error = 'File already exists';
                        return false;
                    } else if (move_uploaded_file($file['tmp_name'], $destination . $file['name'])) {
                        return $destination . $file['name'];
                    } else {
                        $this->error = 'Upload failed';
                        return false;
                    }
                    break;
                default:
                    return false;
                    break;
                }
            }
        }
    }

    /**
     * Generate a resized version of the image while keeping the aspect ration
     * @param string $source Source image file path
     * @param string $output Output image file path
     * @param int $outputWidth Output width in pixels
     * @param int $outputHeight Output height in pixels
     * @return Boolean Returns TRUE when image is successfully resized
     */
    public function resize($source, $output, $outputWidth, $outputHeight)
    {
        //check if ouput size is valid
        if ($outputWidth == 0 || $outputHeight == 0) {
            $this->error = 'Output image dimensions are invalid';
            return false;
        }

        //check if the source image exists and output image is valid
        if ($this->check($source, $output) == false)
            return false;

        //get file type
        $type = explode('.', strtolower($source));
        $type = $type[count($type) - 1];

        switch ($type) {
        case 'png':
            $image = @imagecreatefrompng($source);
            break;
        case 'jpg':
        case 'jpeg':
            $image = @imagecreatefromjpeg($source);
            break;
        case 'gif':
            $image = @imagecreatefromgif($source);
            break;
        default:
            $this->error = 'Invalid source image';
            return false;
        }

        //get source image dimensions
        list($sourceWidth, $sourceHeight) = getimagesize($source);

        if (empty($sourceWidth) || empty($sourceHeight)) {
            $this->error = 'Source image dimensions are invalid';
            return false;
        }

        //correct new image size dimesions
        if ($outputWidth > $outputHeight) {
            $outputWidth = (int) $sourceWidth * ($outputHeight / $sourceHeight);
        } else {
            $outputHeight = (int) $sourceHeight * ($outputWidth / $sourceWidth);
        }

        //create image
        $picture = imagecreatetruecolor($outputWidth, $outputHeight);

        imagecopyresampled($picture, $image, 0, 0, 0, 0, $outputWidth, $outputHeight, $sourceWidth, $sourceHeight);

        imagejpeg($picture, $output, 100);

        //free up memory
        imagedestroy($image);
        imagedestroy($picture);

        return true;
    }

    /**
     * Create a resized version of the original image and cut out the excess
     * dimesnions to fit the output size
     * @param string $source Source image file path
     * @param string $output Output image file path
     * @param int $outputWidth Output image width in pixels
     * @param int $outputHeight Output image height in pixels
     * @return boolean Return TRUE when image is successfully cropped
     */
    public function crop($source, $output, $outputWidth, $outputHeight)
    {
        //check if the size is valid
        if ($outputWidth == 0 || $outputHeight == 0) {
            $this->error = 'Output image dimensions are invalid';
            return false;
        }

        //check if the source image exists and output image is valid
        if ($this->check($source, $output) == false)
            return false;

        //get image type
        $type = explode('.', strtolower($source));
        $type = $type[count($type) - 1];

        switch ($type) {
        case 'png':
            $image = @imagecreatefrompng($source);
            break;
        case 'jpg':
        case 'jpeg':
            $image = @imagecreatefromjpeg($source);
            break;
        case 'gif':
            $image = @imagecreatefromgif($source);
            break;
        default:
            $this->error = 'Invalid source image';
            return false;
        }

        //created a resized version of the image
        list($sourceWidth, $sourceHeight) = getimagesize($source);

        if (empty($sourceWidth) || empty($sourceHeight)) {
            $this->error = 'Source image dimensions are invalid';
            return false;
        }

        $tmpWidth  = $outputWidth;
        $tmpHeight = $outputHeight;

        if ($outputWidth > $outputHeight) {
            $tmpHeight = (int) $sourceHeight * ($outputWidth / $sourceWidth);
        } else {
            $tmpWidth = (int) $sourceWidth * ($outputHeight / $sourceHeight);
        }

        $picture = imagecreatetruecolor($tmpWidth, $tmpHeight);

        imagecopyresampled($picture, $image, 0, 0, 0, 0, $tmpWidth, $tmpHeight, $sourceWidth, $sourceHeight);

        $tmpImage = dirname($source) . "/AUTO_" . uniqid() . ".jpg";

        imagejpeg($picture, $tmpImage, 100);

        //free up memory
        imagedestroy($image);
        imagedestroy($picture);

        $image = @imagecreatefromjpeg($tmpImage);

        //crop the resized image to fit the output dimensions
        list($sourceWidth, $sourceHeight) = getimagesize($tmpImage);

        $x = 0;
        $y = 0;

        if ($sourceWidth > $sourceHeight) {
            $x = (int) ($sourceWidth - $outputWidth) / 2;
        } else {
            $y = (int) ($sourceHeight - $outputHeight) / 2;
        }

        $picture = imagecreatetruecolor($outputWidth, $outputHeight);

        imagecopymerge($picture, $image, 0, 0, $x, $y, $sourceWidth, $sourceHeight, 100);

        imagejpeg($picture, $output, 100);

        //free up memory
        imagedestroy($image);
        imagedestroy($picture);

        unlink($tmpImage);

        return true;
    }

    /**
     * Test wether the source image exists and the output image is valid
     * @param string $source Source image file path
     * @param string $output Output image file path
     * @return boolean Returns true when both source and output image is valid
     */
    private function check($source, $output)
    {
        if (!file_exists($source)) {
            $this->error = 'Source image does not exist';
            return false;
        }

        if (file_exists($output)) {
            $this->error = 'Output image already exists';
            return false;
        }

        $outputType = explode('.', strtolower($output));
        $outputType = $outputType[count($outputType) -1];

        /*as of now jpeg is the only output supported to minimize file size*/
        if ($outputType != 'jpg') {
            $this->error = 'Output image type is not supported';
            return false;
        }

        return true;
    }
}
